//
//  TYZNetworkingTool.m
//  kanhujia
//
//  Created by lxl on 2018/5/14.
//  Copyright © 2018年 lxl. All rights reserved.
//

#import "TYZNetworkingTool.h"
#import <AFNetworking/AFNetworking.h>
#import <SystemConfiguration/CaptiveNetwork.h>
#import <dlfcn.h>
#import "Reachability.h"
#import "TYZDeviceInfo.h"
#import "ESTLoginTool.h"
#import "TYZNetworkPromptView.h"
@interface TYZNetworkingTool ()
@property (nonatomic, strong) Reachability *reachability;
/**
 *  信号名称
 */
@property(nonatomic, strong) NSArray *networkNames;
/**
 *  强度级别
 */
@property(nonatomic, strong) NSArray *intensityNames;
@end

@implementation TYZNetworkingTool
+ (instancetype)initial {
    static dispatch_once_t onceToken;
    static TYZNetworkingTool *instance = nil;
    dispatch_once(&onceToken,^{
        instance = [[TYZNetworkingTool alloc] init];
        [instance setupManager];
        [instance monitorNetworkState];
    });
    return instance;
}
- (AFHTTPSessionManager *)manager {
    if (_manager == nil) {
        _manager = [AFHTTPSessionManager manager];
    }
    return _manager;
}
- (void)setupManager {
    self.manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    self.manager.requestSerializer = [AFJSONRequestSerializer serializer];
    // 告诉服务器请求参数类型
    self.manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects: @"application/json", @"text/json", @"text/javascript",@"text/plain", nil];
    [self.manager.requestSerializer setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    // 设置超时时间
    [self.manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
    self.manager.requestSerializer.timeoutInterval = Request_TimeoutInterval;
    [self.manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
}
- (void)setupCookie {
    [self.manager.requestSerializer setValue:[NSString stringWithFormat:@"session.id=;rememberMe="] forHTTPHeaderField:@"Set-Cookie"];
}

/**
 *  版本检测的参数设置
 */
- (NSDictionary *)setCheckAppVersionParameter {
    NSString *deviceToken = CoreInfo.deviceToken ? CoreInfo.deviceToken : @"";
    NSDictionary *para = @{
                           @"APP_NAME" : APP_ID,
                           @"USER_ID" : @"",
                           @"AUTH_TOKEN" : @"",
                           @"devicetype" : @"2",
                           @"appname" : APP_ID,
                           @"appversion" : [TYZDeviceInfo getAPPVerion],
                           @"model" : [TYZDeviceInfo getDeviceName],
                           @"devicetoken" : deviceToken,
                           @"ipaddress" : @""
                           };
    NSDictionary *body = @{
                           @"functioncode": Code_CheckVersion,
                           @"parameters": para
                           };
    NSDictionary *dict = @{
                           @"encrytype": Request_Encrytype,
                           @"data": @{
                                   @"body": body,
                                   @"servercode": @"2001",
                                   @"isdefault": @"1",
                                   @"lan": @"en-US",
                                   @"devicetoken": deviceToken,
                                   @"user": @""
                                   },
                           @"protocolversion": @"1.0"
                           };
    return [dict copy];
}

/**
 *  登录后的固定参数
 */
- (NSDictionary *)parameter {
    if (_parameter == nil) {
        NSString *userid = UserInfo.userid ? UserInfo.userid : @"";
        NSString *AUTH_TOKEN = UserInfo.AUTH_TOKEN ? UserInfo.AUTH_TOKEN : @"";
        NSString *deviceToken = CoreInfo.deviceToken ? CoreInfo.deviceToken : @"";
        _parameter = @{
                       @"USER_ID" : userid,
                       @"AUTH_TOKEN" : AUTH_TOKEN,
                       @"devicetype" : @"2",
                       @"appname" : APP_ID,
                       @"appversion" : [TYZDeviceInfo getAPPVerion],
                       @"model" : [TYZDeviceInfo getDeviceName],
                       @"devicetoken" : deviceToken,
                       @"ipaddress" : @""
                       };
    }
    return _parameter;
}

/**
 登出参数设置
 
 @return 设置好的参数
 */
- (NSDictionary *)setLogoutWithParameter:(NSDictionary *)parameter {
    NSDictionary *body = @{
                           @"functioncode": Code_Logout,
                           @"parameters": parameter
                           };
    NSDictionary *dict = @{
                           @"encrytype": Request_Encrytype,
                           @"data": @{
                                   @"body": body,
                                   @"servercode": @"1006",
                                   @"isdefault": @"1",
                                   @"lan": @"en-US",
                                   @"devicetoken": CoreInfo.deviceToken,
                                   @"user": UserInfo.userid
                                   },
                           @"protocolversion": @"1.0"
                           };
    return dict;
}

/**
 登录参数设置

 @param parameter 传进来的参数
 @return 设置好的参数
 */
- (NSDictionary *)setLoginWithParameter:(NSDictionary *)parameter {
    NSDictionary *body = @{
                           @"functioncode": Code_Login,
                           @"parameters": parameter
                           };
    NSDictionary *dict = @{
                           @"encrytype": Request_Encrytype,
                           @"data": @{
                                   @"body": body,
                                   @"servercode": @"2001",
                                   @"isdefault": @"1",
                                   @"lan": @"en-US",
                                   @"devicetoken": CoreInfo.deviceToken,
                                   @"user": @""
                                   },
                           @"protocolversion": @"1.0"
                           };
    return dict;
}

/**
 一般参数设置

 @param code 请求代码
 @param parameter 传进来的参数
 @return 设置好的参数
 */
- (NSDictionary *)setParameterWithCode:(NSString *)code parameter:(NSDictionary *)parameter {
    NSDictionary *body = @{
                           @"functioncode": code,
                           @"parameters": parameter
                           };
    NSDictionary *dict = @{
                           @"encrytype": Request_Encrytype,
                           @"data": @{
                                   @"body": body,
                                   @"servercode": @"2001",
                                   @"isdefault": @"1",
                                   @"lan": @"en-US",
                                   @"devicetoken": CoreInfo.deviceToken,
                                   @"user": UserInfo.userid ? UserInfo.userid : @""
                                   },
                           @"protocolversion": @"1.0"
                           };
    return dict;
}
- (NSDictionary *)setBodParameteryWithParameter:(NSDictionary *)parameter {
    NSMutableDictionary *dictM = [NSMutableDictionary dictionaryWithDictionary:parameter];
    [dictM addEntriesFromDictionary:self.parameter];
    return [dictM mutableCopy];
}

/**
 检测版本

 @param compelment 完成回调
 */
- (void)checkAppVersionCompelment:(void(^)(NSArray *result))compelment {
    NSDictionary *parameter = [self setCheckAppVersionParameter];
    [self sendPostWithCode:nil parameter:parameter success:^(NSDictionary *result) {
        if (compelment) {
            compelment((NSArray *)result);
        }
    } failure:^(NSString *error) {
        if (compelment) {
            compelment(nil);
        }
    }];
}
/**
 账号登出

 @param complement 登出完成
 */
- (void)logoutWithComplement:(void(^)(NSString *result))complement {
    NSDictionary *parameter = [self setLogoutWithParameter:[self setBodParameteryWithParameter:@{@"userid" : UserInfo.userid}]];
    [NetTool sendPostWithCode:Code_Logout parameter:parameter success:^(NSDictionary *result) {
        if (complement) {
            complement(Request_Success);
        }
    } failure:^(NSString *error) {
        if ([error containsString:[@"成功" S]]) {
            if (complement) {
                complement(Request_Success);
            }
        } else {
            if (complement) {
                complement(Request_Failed);
            }
        }
    }];
}

/**
 用户登录

 @param userName 用户名
 @param password 密码
 @param complement 登录完成
 */
- (void)logginWithUserName:(NSString *)userName password:(NSString *)password complement:(void(^)(NSDictionary *result))complement {
    NSDictionary *dict = @{
                           @"APP_ID": APP_ID,
                           @"LOGIN_NAME": userName,
                           @"PASSWORD": password,
                           @"username": userName,
                           @"password": password,
                           @"IS_AUTO": @"0",
                           @"DEVICE_ID": [TYZDeviceInfo getDeviceID],
                           @"APP_NAME": APP_NAME,
                           @"DEVICE_NAME": [TYZDeviceInfo getiPhoneName],
                           @"DEVICE_MODEL": [TYZDeviceInfo getDeviceName],
                           @"DEVICE_IP": @"",
                           @"devicetoken": CoreInfo.deviceToken,
                           @"devicetype": @"2",
                           @"appname": APP_ID,
                           @"appversion": [TYZDeviceInfo getAPPVerion],
                           @"ipaddress": @"",
                           @"USER_ID": @"",
                           @"AUTH_TOKEN": @"",
                           @"model": [TYZDeviceInfo getDeviceName]
                           };
    NSDictionary *parameter = [self setLoginWithParameter:dict];
    [NetTool sendPostWithCode:Code_Login parameter:parameter success:^(NSDictionary *result) {
        if (complement) {
            complement(result);
        }
    } failure:^(NSString *error) {
        [TYZLoadingView showError:error];
    }];
}

/**
 POST请求

 @param code 请求代码
 @param parameter 请求参数
 @param success 请求成功
 @param failure 请求失败
 */
- (void)postWithCode:(NSString *)code parameter:(NSDictionary *)parameter success:(void (^)(NSDictionary *result))success failure:(void (^)(NSString *error))failure {
    if (!code || !parameter) return;
    NSDictionary *dict = [self setParameterWithCode:code parameter:[self setBodParameteryWithParameter:parameter]];
    [self sendPostWithCode:code parameter:dict success:success failure:failure];
}

/**
 最后的POST请求发送

 @param code 请求代码（用于请求失败的告知）
 @param parameter 参数
 @param success 请求成功
 @param failure 请求失败
 */
- (void)sendPostWithCode:(NSString *)code parameter:(NSDictionary *)parameter success:(void (^)(NSDictionary *result))success failure:(void (^)(NSString *error))failure {
    if ([NSJSONSerialization isValidJSONObject:parameter]) {
        [self.manager POST:self.url parameters:parameter progress:^(NSProgress * _Nonnull uploadProgress) {
            
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self successWithCode:code parameter:parameter responseObject:responseObject success:success failure:failure];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self failureWithCode: code parameter:parameter error:error success:success failure:failure];
        }];
    } else {
        NSLog(@"%@:%@", code, Parameter_Error);
        failure(Parameter_Error);
    }
}
- (void)successWithCode:(NSString *)code parameter:(NSDictionary *)parameter responseObject:(id)responseObject success:(void (^)(NSDictionary *result))success failure:(void (^)(NSString *error))failure {
    [TYZNetworkPromptView hiddennetworkCutOffView];
    NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    NSDictionary *dict = [self dictionaryWithJsonString:[string URLDecodedString]];
    if (dict && [dict isKindOfClass:[NSDictionary class]]) {
        NSDictionary *data = dict[Request_Data];
        if (data && [data isKindOfClass:[NSDictionary class]]) {
            if ([data[Request_ErrorMassage] isEqualToString:Request_Success]) {
                NSDictionary *body = data[Request_Body];
                if (body && [body isKindOfClass:[NSDictionary class]]) {
                    if ([body[Request_Error] isEqualToString:Request_Success_Code]) {
                        if (success) {
                            success(body[Request_Result]);
                            return;
                        }
                    } else {
                        if (failure) {
                            NSLog(@"%@:%@", code, body[Request_ErrorMessage]);
                            // 用户未登录
                            if ([body[Request_ErrorMessage] isEqualToString:Err_UserNoLogin]) {
                                if (CoreInfo.userName && CoreInfo.password) {
                                    [self requestAgainWithCode:code parameter:parameter success:success failure:failure];
                                    return;
                                }
                            }
                            failure(body[Request_ErrorMessage]);
                            return;
                        }
                    }
                }
            }
        }
    }
    if (failure) {
        NSLog(@"%@:%@", code, Request_Success_Error);
        failure(nil);
    }
}
- (void)failureWithCode:(NSString *)code parameter:(NSDictionary *)parameter error:(NSError *)error success:(void (^)(NSDictionary *result))success failure:(void (^)(NSString *error))failure {
    if (failure) {
        [TYZLoadingView hideHUD];
        NSString *string = error.localizedDescription;
        if ([string hasPrefix:[@"请求超时" S]]) {
            string = ConnectTimedOut_CUS;
        } else if ([string hasPrefix:CouldNotConnect_AFN]) {// 无法连接到服务器
            string = CouldNotConnect_CUS;
        } else if ([string hasPrefix:ConnectTimedOut_AFN]) {// 连接超时
            string = ConnectTimedOut_CUS;
        } else if ([string hasPrefix:ConnectionLost_AFN]) {
            string = ConnectionLost_CUS;
        } else if ([string hasPrefix:ConnectionBreak_AFN]) { // 飞行模式
            string = ConnectionBreak_CUS;
        }
        NSLog(@"%@ %@", code, string);
        failure(string);
        WEAKSELF
        if ([code integerValue] <= [Code_Value_List integerValue]) return;
        [TYZNetworkPromptView networkCutOffViewWithAgain:^{
            [weakSelf sendPostWithCode:code parameter:parameter success:success failure:failure];
        }];
    }
    if (NetTool.networkType == NetworkType_None) {
        [TYZSystemDialog dialogWithTitle:[@"当前网络不可达\n请前往检查网络设置" S] complement:^{
            [TYZCoreInfo pushToDeviceSettingWithPushSettingType:PushSettingType_MOBILE_DATA_SETTINGS_ID];
        }];
    }
}
- (void)requestAgainWithCode:(NSString *)code parameter:(NSDictionary *)parameter success:(void (^)(NSDictionary *result))success failure:(void (^)(NSString *error))failure {
    if (parameter) {
        WEAKSELF
        __weak typeof(parameter) weakDict = parameter;
        [ESTLoginTool loginWithUserAccount:CoreInfo.userName password:CoreInfo.password loginSuccess:^(NSInteger integer) {
            
        } complement:^(NSString *result) {
            if ([result isEqualToString:Login_Success]) {
                [weakSelf sendPostWithCode:code parameter:weakDict success:success failure:failure];
            } else {
                [TYZLoadingView showError:UserLoginFailure];
            }
        }];
    } else {
        [TYZLoadingView showError:UnusualExitAgain];
    }
}
#pragma mark - 监测网络状态和强度
- (void)monitorNetworkState {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:)name:kReachabilityChangedNotification object: nil];
    NSString *remoteHostName = TYZ_NETWORK_ADDRESS;
    self.reachability = [Reachability reachabilityWithHostName:remoteHostName];
    [self.reachability startNotifier];
}
- (void)reachabilityChanged:(NSNotification *)notification{
    Reachability *curReach = [notification object];
    NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
    NetworkStatus status = [curReach currentReachabilityStatus];
    switch (status) {
        case NotReachable:
            NSLog(@"====当前网络不可达=======");
            self.networkType = NetworkType_None;
            break;
        default:
            NSLog(@"====当前网络连接中=======");
            self.networkType = [self networkStateType];
            NSLog(@"%@：%zd - %@", self.networkNames[self.networkType], self.intentsityValue, self.intensityNames[self.networkIntensity]);
            break;
    }
}
- (NetworkType)networkStateType {
    UIApplication *app = [UIApplication sharedApplication];
    if (KIsiPhoneX == NO) {
        NSArray *subviews = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
        for (id subview in subviews) {
            if ([subview isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
                int networkType = [[subview valueForKeyPath:@"dataNetworkType"] intValue];
                self.networkIntensity = [self getSignalLevelWithType:networkType subview:subview];
                switch (networkType) {
                    case 1:
                        return NetworkType_2G;
                    case 2:
                        return NetworkType_3G;
                    case 3:
                        return NetworkType_4G;
                    case 5:
                        return NetworkType_Wifi;
                    default:
                        return NetworkType_None;
                }
            }
        }
    }
    return NetworkType_None;
}
- (NetworkIntensity)getSignalLevelWithType:(NSInteger)networkType subview:(NSDictionary *)subview {
    if (networkType == 0) {
        return NetworkIntensity_Default;
    } else if (networkType == 5) {
        self.intentsityValue = [[subview valueForKeyPath:@"wifiStrengthRaw"] intValue];
        if (self.intentsityValue > WIFIValueHigh) {
            return NetworkIntensity_High;
        } else if (self.intentsityValue > WIFIValueLow) {
            return NetworkIntensity_Mid;
        } else {
            return NetworkIntensity_Low;
        }
    } else {
        // 此API是apple私有API，所以只可运用在越狱设备中，如果提交appstore，会遭遇apple的拒绝上架反馈！
        void *libHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony",RTLD_LAZY);
        int (*CTGetSignalStrength)(void);
        CTGetSignalStrength = (int(*)(void))dlsym(libHandle,"CTGetSignalStrength");
        if(CTGetSignalStrength == NULL) {
            return NetworkIntensity_Default;
        } else {
            self.intentsityValue = CTGetSignalStrength();
            dlclose(libHandle); //切记关闭库
            if (self.intentsityValue > SIMValueHigh) {
                return NetworkIntensity_High;
            } else if (self.intentsityValue > SIMValueLow) {
                return NetworkIntensity_Mid;
            } else {
                return NetworkIntensity_Low;
            }
        }
    }
}
- (NSArray *)networkNames {
    if (_networkNames == nil) {
        _networkNames = @[@"无连接", @"Wifi", @"2G", @"3G", @"4G"];
    }
    return _networkNames;
}
- (NSArray *)intensityNames {
    if (_intensityNames == nil) {
        _intensityNames = @[@"没有信号", @"低", @"中", @"高"];
    }
    return _intensityNames;
}
#pragma mark - 数据转换
// 字典转json字符串方法
- (NSString *)convertToJsonData:(NSDictionary *)dict {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
    NSString *jsonString;
    if (!jsonData) {
        NSLog(@"%@",error);
    } else {
        jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    NSRange range = {0,jsonString.length};
    //去掉字符串中的空格
    [mutStr replaceOccurrencesOfString:@" " withString:@"" options:NSLiteralSearch range:range];
    NSRange range2 = {0,mutStr.length};
    //去掉字符串中的换行符
    [mutStr replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:range2];
    return mutStr;
}
// JSON字符串转化为字典
- (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
    if (jsonString == nil) return nil;
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *err;
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
                                                        options:NSJSONReadingMutableContainers
                                                          error:&err];
    if (err) {
        NSLog(@"json解析失败：%@",err);
        return nil;
    }
    return dic;
}
@end
